#pragma once

namespace ECameraChange
{
	enum Flag
	{
		WorldPosition				= 1 << 0,
		Rotation					= 1 << 1,
		FieldOfView					= 1 << 2,

		All							= ~0
	};
}

class Camera
{
public:
	Camera(const glm::vec4& viewport, float farDist, float nearDist, float fovDeg);
	~Camera();

	const glm::vec3&	GetWorldPosition() const;
	void				AddWorldPosition(const glm::vec3& diff);
	void				AddWorldPositionX(float diff);
	void				AddWorldPositionY(float diff);
	void				AddWorldPositionZ(float diff);
	void				SetWorldPosition(const glm::vec3& pos);

	const glm::quat&	GetRotation() const;
	void				AddRotationX(float deg);
	void				AddRotationY(float deg);
	void				AddRotationZ(float deg);
	void				MoveX(float diff);
	void				MoveY(float diff);
	void				MoveZ(float diff);
	void				SetRotation(const glm::quat& quat);

	float				GetFarDistance() const;
	float				GetNearDistance() const;

	float				GetFoV() const;
	void				SetFov(float fov);

	const GLM_MAT4x4&	GetViewMatrix();
	const GLM_MAT4x4&	GetProjectionMatrix();


private:
	void				Update();
	void				UpdateViewMatrix();
	void				UpdateProjectionMatrix();
	void				UpdateFrustum();

	glm::vec3			m_worldPosition;
	glm::quat			m_rotation;
	float				m_fovDeg;
	
	ATTRIBUTE_ALIGNED16(GLM_MAT4x4)			m_viewMatrix;
	ATTRIBUTE_ALIGNED16(GLM_MAT4x4)			m_projectionMatrix;

	glm::vec4			m_viewport;
	float				m_nearDistance;
	float				m_farDistance;

	// frustum planes
	glm::vec4			m_planeLeft;
	glm::vec4			m_planeRight;
	glm::vec4			m_planeBottom;
	glm::vec4			m_planeTop;
	glm::vec4			m_planeNear;
	glm::vec4			m_planeFar;

	float				m_rotationSpeed;
	float				m_movementSpeed;

	uint				m_dirtyBits;
};

